package web

import (
	"log"
	"net"
	"net/http"
)

// HandleFunc 路由处理方法
type HandleFunc func(ctx *Context)

var _ Server = &HttpServer{}

// Server 服务接口
type Server interface {
	// Handler 组合原生http处理方法
	http.Handler
	// Start 服务启动方法
	Start(addr string) error
	// AddRoute 添加路由方法
	AddRoute(method, path string, handler HandleFunc, midls ...Middleware)
}

type HttpServerOption func(server *HttpServer)

type HttpServer struct {
	router
	middles   []Middleware
	log       func(msg string, args ...any)
	tplEngine TemplateEngine
}

func NewHttpServer(opts ...HttpServerOption) *HttpServer {
	server := &HttpServer{
		router: newRouter(),
		log: func(msg string, args ...any) {
			log.Printf(msg, args...)
		},
	}

	for _, opt := range opts {
		opt(server)
	}
	return server
}
func ServerWithTemplateEngine(tplEngine TemplateEngine) HttpServerOption {
	return func(server *HttpServer) {
		server.tplEngine = tplEngine
	}
}

func ServerWithMiddleware(mdls ...Middleware) HttpServerOption {
	return func(serve *HttpServer) {
		serve.middles = mdls
	}
}

// server 路由业务逻辑处理方法
func (h *HttpServer) server(ctx *Context) {
	route, ok := h.findRoute(ctx.Req.Method, ctx.Req.URL.Path)
	if !ok || route.n.handler == nil {
		ctx.RespStatusCode = http.StatusNotFound
		ctx.RespData = []byte("PAGE NOT FOUND")
		return
	}
	ctx.PathParams = route.pathParam
	ctx.MatchRoute = route.n.route
	handler := route.n.handler
	// 组装中间件
	for i := len(route.n.mdls) - 1; i >= 0; i-- {
		mdlsFunc := route.n.mdls[i]
		if mdlsFunc != nil {
			handler = mdlsFunc(handler)
		}
	}
	handler(ctx)
}

func (h *HttpServer) flushResp(ctx *Context) {
	if ctx.RespStatusCode != 0 {
		ctx.Resp.WriteHeader(ctx.RespStatusCode)
	}
	n, err := ctx.Resp.Write(ctx.RespData)
	if err != nil || n != len(ctx.RespData) {
		h.log("写入响应失败 %v", err)
	}
}

// ServerHttp 初始化http服务句柄
func (h *HttpServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	ctx := &Context{
		Req:        request,
		Resp:       writer,
		PathParams: make(map[string]string),
		tplEngine:  h.tplEngine,
	}
	// root 是一个方法,使用变量存储暂时不调用
	root := h.server
	for i := len(h.middles) - 1; i >= 0; i-- {
		root = h.middles[i](root)
	}

	var m Middleware = func(next HandleFunc) HandleFunc {
		return func(ctx *Context) {
			next(ctx)
			h.flushResp(ctx)
		}
	}

	root = m(root)

	root(ctx)
}

// Start 启动http服务
func (h *HttpServer) Start(addr string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	// 这里有两个参数，分别的决定监听什么服务，以及监听服务处理的对象
	return http.Serve(listener, h)
}

func (h *HttpServer) AddRoute(method, path string, handler HandleFunc, midls ...Middleware) {
	h.router.addRoute(method, path, handler, midls)
}

func (h *HttpServer) AddMiddleware(mid Middleware) {
	h.middles = append(h.middles, mid)
}
